/*
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  
  Modified 23 November 2006 by David A. Mellis
*/

#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include "HardwareSerial.h"

HardwareSerial1 Serial;

//===========================================================================

OPTIMIZE_SIZE void HardwareSerial1::printNumber(unsigned long n, uint8_t base)
{
	unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
	unsigned long i = 0;

	if (n == 0) {
		print('0');
		return;
	}

	while (n > 0) {
		buf[i++] = n % base;
		n /= base;
	}

	for (; i > 0; i--)
	print((char) (buf[i - 1] < 10 ?
	'0' + buf[i - 1] :
	'A' + buf[i - 1] - 10));
}

OPTIMIZE_SIZE void HardwareSerial1::printFloat(double number, uint8_t digits)
{
	// Handle negative numbers
	if (number < 0.0)
	{
		print('-');
		number = -number;
	}

	// Round correctly so that print(1.999, 2) prints as "2.00"
	double rounding = 0.5;
	for (uint8_t i=0; i<digits; ++i)
	rounding /= 10.0;
	
	number += rounding;

	// Extract the integer part of the number and print it
	unsigned long int_part = (unsigned long)number;
	double remainder = number - (double)int_part;
	print(int_part);

	// Print the decimal point, but only if there are digits beyond
	if (digits > 0)
	print(".");

	// Extract digits from the remainder one at a time
	while (digits-- > 0)
	{
		remainder *= 10.0;
		int toPrint = int(remainder);
		print(toPrint);
		remainder -= toPrint;
	}
}

OPTIMIZE_SIZE void HardwareSerial1::print(long n)
{
	if (n < 0) {
		print('-');
		n = -n;
	}
	printNumber(n, 10);
}

OPTIMIZE_SIZE void HardwareSerial1::print(long n, int base)
{
	if (base == 0)
	print((char) n);
	else if (base == 10)
	print(n);
	else
	printNumber(n, base);
}

OPTIMIZE_SIZE void HardwareSerial1::print(const char c[])
{
	while (*c)
		write(*c++);
}

OPTIMIZE_SIZE void HardwareSerial1::print_P(PGM_P s)
{
	char c;
	
	while ((c = pgm_read_byte_far(s++)) != 0)
		write(c);
}